using Gateway.Common.Enums;
using Gateway.Common.Models;
using Gateway.Domain.Entities;
using Gateway.Domain.Model;
using Gateway.IApplication.BaseInput;
using Gateway.IApplication.WorkFlow;
using Gateway.IApplication.WorkFlow.Input;
using Gateway.IApplication.WorkFlow.Input.Design;
using Gateway.IRepositories;
using Microsoft.EntityFrameworkCore;

namespace Gateway.Application;
/// <summary>
/// 
/// </summary>
public class WorkFlowApp : IWorkFlowApp
{
    private readonly IAppRepository<WorkFlow> _repository;
    private readonly IAppRepository<WorkFlowDesign> _designRepository;
    private readonly IUnitOfWork _unitOfWork;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="repository"></param>
    /// <param name="unitOfWork"></param>
    /// <param name="designRepository"></param>
    public WorkFlowApp(IAppRepository<WorkFlow> repository, IUnitOfWork unitOfWork,
        IAppRepository<WorkFlowDesign> designRepository)
    {
        _repository = repository;
        _unitOfWork = unitOfWork;
        _designRepository = designRepository;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="MyException"></exception>
    public async Task<bool> Add(CreateWorkFlowInput input)
    {
        var exist = await _repository.FirstOrDefaultAsync(p =>
            p.WorkFlowCode.Equals(input.WorkFlowCode) && p.Deleted == BooleanStatusEnum.No);
        if (exist != null)
        {
            throw new MyException("已存在相同编码的流程");
        }

        var entity = new WorkFlow(workFlowCode: input.WorkFlowCode, workFlowName: input.WorkFlowName);
        await _repository.AddAsync(entity);
        await _unitOfWork.CommitAsync();
        return true;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="MyException"></exception>
    public async Task<bool> Update(UpdateWorkFlowInput input)
    {
        var exist = await _repository.FirstOrDefaultAsync(p =>
            p.WorkFlowCode.Equals(input.WorkFlowCode) && p.Deleted == BooleanStatusEnum.No &&
            !p.Id.Equals(input.WorkFlowId));
        if (exist != null)
        {
            throw new MyException("已存在相同编码的流程");
        }

        var entity = await _repository.FirstOrDefaultAsync(p =>
            p.Id.Equals(input.WorkFlowId));
        if (entity == null)
        {
            throw new MyException(SystemErrorCode.DataIsNotAvailable);
        }

        entity.Update(workFlowCode: input.WorkFlowCode, workFlowName: input.WorkFlowName);
        await _repository.UpdateAsync(entity);
        await _unitOfWork.CommitAsync();
        return true;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="MyException"></exception>
    public async Task<bool> Disable(DisableInput input)
    {
        var entity = await _repository.FirstOrDefaultAsync(p =>
            p.Id.Equals(input.Id));
        if (entity == null)
        {
            throw new MyException(SystemErrorCode.DataIsNotAvailable);
        }

        entity.SetDisabled(input.Disable);
        await _repository.UpdateAsync(entity);
        await _unitOfWork.CommitAsync();
        return true;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="MyException"></exception>
    public async Task<bool> Remove(RemoveInput input)
    {
        var entity = await _repository.FirstOrDefaultAsync(p =>
            p.Id.Equals(input.Id));
        if (entity == null)
        {
            throw new MyException(SystemErrorCode.DataIsNotAvailable);
        }

        entity.SetDeleted();
        await _repository.UpdateAsync(entity);
        await _unitOfWork.CommitAsync();
        return true;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<bool> Design(WorkFlowDesignInput input)
    {
        if (!string.IsNullOrEmpty(input.WorkFlowDesignId))
        {
            var entity = new WorkFlowDesign(nodeName: input.NodeName, type: input.Type,
                promoter: input.Promoter != null
                    ? new WorkFlowDesignPromoter()
                    {
                        NodeRoles = input.Promoter.NodeRoles.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,                                
                            Name = p.Name
                        }).ToList()
                    }
                    : null,
                branch: input.Branch != null
                    ? new WorkFlowDesignBranch()
                    {
                        Conditions = input.Branch.Conditions.Select(p => new BranchCondition()
                        {
                            ConditionMode = p.ConditionMode,
                            Description = p.Description,
                            Field = p.Field, Operator = p.Operator, Value = p.Value
                        }).ToList()
                    }
                    : null,
                approve: input.Approve != null
                    ? new WorkFlowDesignApprove()
                    {
                        ApproveType = input.Approve.ApproveType,
                        DirectorLevel = input.Approve.DirectorLevel,
                        DirectorMode = input.Approve.DirectorMode,
                        ExamineLevel = input.Approve.ExamineLevel,
                        ExamineMode = input.Approve.ExamineMode,
                        SelectMode = input.Approve.SelectMode,
                        Term = input.Approve.Term,
                        TermMode = input.Approve.TermMode,
                        TermAutoStatus = BooleanStatusEnum.FromValue(input.Approve.TermAutoStatus ?? "N"),
                        NodeRole = input.Approve.NodeRole?.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,
                            Name = p.Name
                        }).ToList(),
                        WorkDesignNodeRoleOrUser = input.Approve.WorkDesignNodeRoleOrUser != null
                            ? new WorkDesignNodeRoleOrUser()
                            {
                                Id = input.Approve.WorkDesignNodeRoleOrUser.Id,
                                Name = input.Approve.WorkDesignNodeRoleOrUser.Name
                            }
                            : null
                    }
                    : null,
                send: input.Send != null
                    ? new WorkFlowDesignSend()
                    {
                        NodeUsers = input.Send.NodeUsers?.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,
                            Name = p.Name
                        }).ToList(),
                        UserSelect = BooleanStatusEnum.FromValue(input.Send.UserSelect ?? "N")
                    }
                    : null
            );
        }
        else
        {
            var entity = await _designRepository.Entities.Include(x => x.Approve)
                .Include(x => x.Branch)
                .Include(x => x.Promoter)
                .Include(x => x.Send)
                .Where(x => x.Id.Equals(input.WorkFlowDesignId)).FirstOrDefaultAsync();
            entity.Update(nodeName: input.NodeName, type: input.Type,
                promoter: input.Promoter != null
                    ? new WorkFlowDesignPromoter()
                    {
                        NodeRoles = input.Promoter.NodeRoles.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,                                
                            Name = p.Name
                        }).ToList()
                    }
                    : null,
                branch: input.Branch != null
                    ? new WorkFlowDesignBranch()
                    {
                        Conditions = input.Branch.Conditions.Select(p => new BranchCondition()
                        {
                            ConditionMode = p.ConditionMode,
                            Description = p.Description,
                            Field = p.Field, Operator = p.Operator, Value = p.Value
                        }).ToList()
                    }
                    : null,
                approve: input.Approve != null
                    ? new WorkFlowDesignApprove()
                    {
                        ApproveType = input.Approve.ApproveType,
                        DirectorLevel = input.Approve.DirectorLevel,
                        DirectorMode = input.Approve.DirectorMode,
                        ExamineLevel = input.Approve.ExamineLevel,
                        ExamineMode = input.Approve.ExamineMode,
                        SelectMode = input.Approve.SelectMode,
                        Term = input.Approve.Term,
                        TermMode = input.Approve.TermMode,
                        TermAutoStatus = BooleanStatusEnum.FromValue(input.Approve.TermAutoStatus ?? "N"),
                        NodeRole = input.Approve.NodeRole?.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,
                            Name = p.Name
                        }).ToList(),
                        WorkDesignNodeRoleOrUser = input.Approve.WorkDesignNodeRoleOrUser != null
                            ? new WorkDesignNodeRoleOrUser()
                            {
                                Id = input.Approve.WorkDesignNodeRoleOrUser.Id,
                                Name = input.Approve.WorkDesignNodeRoleOrUser.Name
                            }
                            : null
                    }
                    : null,
                send: input.Send != null
                    ? new WorkFlowDesignSend()
                    {
                        NodeUsers = input.Send.NodeUsers?.Select(p => new WorkDesignNodeRoleOrUser()
                        {
                            Id = p.Id,
                            Name = p.Name
                        }).ToList(),
                        UserSelect = BooleanStatusEnum.FromValue(input.Send.UserSelect ?? "N")
                    }
                    : null);
        }

        return true;
    }
}